/*
 * Copyright (c) 2006-2021, Ulandlink Development Team
 * SPDX-License-Identifier: Apache-2.0
 * Change Logs:
 * Date           Author       Notes
 * 2021-12-06      zkw		first version
 */
#include "os_evt.h"
#include "app_ocpp_util.h"
#include "app_ocpp_mgnt_msg.h"
#include "app_websocket_mgnt_mp.h"
#include "app_websocket_ocpp_drv.h"
#include "app_websocket_mgnt_util.h"
#include "app_ocpp_client_req.h"
#include "app_ocpp_server_req.h"

#define LOG_TAG "ocpp.websocket.drv"
#define LOG_LVL LOG_LVL_INFO
#include "ulog.h"

typedef int (*ocpp_msg_handle_up_send_func)(char *payload, uint16_t payload_len);
typedef int (*ocpp_msg_handle_up_recv_func)(char *payload);

typedef int (*ocpp_msg_handle_down_send_func)(char *payload, uint16_t payload_len, uint32_t resp_status);
typedef int (*ocpp_msg_handle_down_recv_func)(char *payload);

typedef struct {
    char *ocpp_action_name;
    ocpp_msg_handle_up_send_func send_proc;
    ocpp_msg_handle_up_recv_func recv_proc;
    char uid[MessageIdType];
} app_ocpp_up_data_handle_t;

typedef struct {
    char *ocpp_action_name;
    ocpp_msg_handle_down_send_func send_proc;
    ocpp_msg_handle_down_recv_func recv_proc;
    char uid[MessageIdType];
} app_ocpp_down_data_handle_t;

static app_ocpp_up_data_handle_t app_ocpp_up_data_proc[] =
    {
        {"connect", 							NULL, 											NULL},
        {"Authorize", 							ocpp_pack_authorize, 							ocpp_unpack_authorize},
        {"BootNotification", 					ocpp_pack_boot_notification, 					ocpp_unpack_boot_notification},
        {"DataTransfer", 						ocpp_pack_data_transfer, 						ocpp_unpack_data_transfer},
        {"DiagnosticsStatusNotification", 		ocpp_pack_diagnostics_status_notification, 		ocpp_unpack_diagnostics_status_notification},
        {"FirmwareStatusNotification", 			ocpp_pack_firmware_status_notification, 		ocpp_unpack_firmware_status_notification},
        {"Heartbeat", 							ocpp_pack_heartbeat, 							ocpp_unpack_heartbeat},
        {"MeterValues", 						ocpp_pack_meter_values, 						ocpp_unpack_meter_values},
        {"StartTransaction", 					ocpp_pack_start_transaction, 					ocpp_unpack_start_transaction},
        {"StatusNotification", 					ocpp_pack_status_notification, 					ocpp_unpack_status_notification},
        {"StopTransaction", 					ocpp_pack_stop_transaction, 					ocpp_unpack_stop_transaction},

};

static app_ocpp_down_data_handle_t app_ocpp_down_data_proc[] =
    {
        {"CancelReservation", 		ocpp_pack_cancel_reservation, 				ocpp_unpack_cancel_reservation},
        {"ChangeAvailability", 		ocpp_pack_change_availability, 				ocpp_unpack_change_availability},
        {"ChangeConfiguration", 	ocpp_pack_change_configuration, 			ocpp_unpack_change_configuration},
        {"ClearCache", 				ocpp_pack_clear_cache, 						ocpp_unpack_clear_cache},
        {"ClearChargingProfile", 	ocpp_pack_clear_charging_profile, 			ocpp_unpack_clear_charging_profile},
#if defined(A5158_EDITION)
        {"DataTransfer", 			ocpp_pack_data_transfer_3rd_server, 		ocpp_unpack_data_transfer_3rd_server},
#else
        {"DataTransfer", 			ocpp_pack_data_transfer_server, 			ocpp_unpack_data_transfer_server},
#endif
        {"GetCompositeSchedule", 	ocpp_pack_get_composite_schedule, 			ocpp_unpack_get_composite_schedule},
        {"GetConfiguration", 		ocpp_pack_get_configuration, 				ocpp_unpack_get_configuration},
        {"GetDiagnostics", 			ocpp_pack_get_diagnostics, 					ocpp_unpack_get_diagnostics},
        {"GetLocalListVersion", 	ocpp_pack_get_localList_version, 			ocpp_unpack_get_localList_version},
        {"RemoteStartTransaction",	ocpp_pack_remote_start_transaction, 		ocpp_unpack_remote_start_transaction},
        {"RemoteStopTransaction", 	ocpp_pack_remote_stop_transaction, 			ocpp_unpack_remote_stop_transaction},
        {"ReserveNow", 				ocpp_pack_reserve_now, 						ocpp_unpack_reserve_now},
        {"Reset", 					ocpp_pack_reset, 							ocpp_unpack_reset},
        {"SendLocalList", 			ocpp_pack_send_LocalList, 					ocpp_unpack_send_LocalList},
        {"SetChargingProfile", 		ocpp_pack_set_charging_profile, 			ocpp_unpack_set_charging_profile},
        {"TriggerMessage", 			ocpp_pack_trigger_message, 					ocpp_unpack_trigger_message},
        {"UnlockConnector", 		ocpp_pack_unlock_connector, 				ocpp_unpack_unlock_connector},
        {"UpdateFirmware", 			ocpp_pack_update_firmware, 					ocpp_unpack_update_firmware},
};

static app_ocpp_up_data_handle_t ocpp_up_15118_data_proc[] =
    {
        {"Authorize", 					ocpp_pack_15118_authorize, 			ocpp_unpack_15118_authorize},
        {"Get15118EVCertificate", 		ocpp_pack_15118_get_ev_cert, 		ocpp_unpack_15118_get_ev_cert},
        {"GetCertificateStatus", 		ocpp_pack_15118_get_cert_status, 	ocpp_unpack_15118_get_cert_status},
        {"SignCertificate", 			ocpp_pack_15118_sign_cert, 			ocpp_unpack_15118_sign_cert},
};

static app_ocpp_down_data_handle_t ocpp_down_15118_data_proc[] =
    {
        {"CertificateSigned", 				ocpp_pack_15118_cert_sign, 				ocpp_unpack_15118_cert_sign},
        {"DeleteCertificate", 				ocpp_pack_15118_delete_cert, 			ocpp_unpack_15118_delete_cert},
        {"GetInstalledCertificateIds", 		ocpp_pack_15118_get_inst_cert_ids, 		ocpp_unpack_15118_get_inst_cert_ids},
        {"InstallCertificate", 				ocpp_pack_15118_install_cert, 			ocpp_unpack_15118_install_cert},
        {"Update15118EVCertificate", 		ocpp_pack_15118_delete_cert, 			ocpp_unpack_15118_delete_cert},
        {"ExtendedTriggerMessage", 			ocpp_pack_15118_ex_trigger_message, 	ocpp_unpack_15118_ex_trigger_message},
};

int app_ocpp_util_next_uid(void) {
    static int ocpp_uid = 0;
    ocpp_uid++;
    return (ocpp_uid);
}

/*
 *接收到ocpp_mngt发送请求 处理
 */
bool app_ocpp_util_send_proc(UINT16 msg_type, UINT16 action_type, uint32_t result_type, uint32_t extend_type) {
#define PACK_BUFF_SIZE (4096)
#define SEND_BUFF_SIZE (4608)

    char *send_buff = RT_NULL;
    char *pack_buff = RT_NULL;
    bool ret = false;
    int pack_result = 1;

    send_buff = (char *)rt_calloc(1, SEND_BUFF_SIZE);
    if (send_buff == RT_NULL) {
        goto exit;
    }

    pack_buff = (char *)rt_calloc(1, PACK_BUFF_SIZE);
    if (pack_buff == RT_NULL) {
        goto exit;
    }

    if (E_OCPP_MESSAGE_CALL == msg_type) {
        if (action_type > E_OCPP_CONNECT && action_type < E_OCPP_SEND_ACTION_MAX) {
            if (E_OCPP_DATA_TRANSFER_CLINET == action_type) {
                snprintf(ocpp_up_15118_data_proc[extend_type].uid, sizeof(ocpp_up_15118_data_proc[extend_type].uid),
                         "%d", app_ocpp_util_next_uid());
                pack_result = ocpp_up_15118_data_proc[extend_type].send_proc(pack_buff, PACK_BUFF_SIZE);
                if (pack_result < 0) {
                    goto exit;
                }
                snprintf((char *)send_buff, SEND_BUFF_SIZE, "[%d,\"%s\",\"%s\",%s]", E_OCPP_MESSAGE_CALL,
                         ocpp_up_15118_data_proc[extend_type].uid,
                         app_ocpp_up_data_proc[action_type].ocpp_action_name,
                         pack_buff);
            } else {
                snprintf(app_ocpp_up_data_proc[action_type].uid, sizeof(app_ocpp_up_data_proc[action_type].uid), "%d", app_ocpp_util_next_uid());
                pack_result = app_ocpp_up_data_proc[action_type].send_proc(pack_buff, PACK_BUFF_SIZE);
                if (pack_result < 0) {
                    goto exit;
                }
                snprintf((char *)send_buff, SEND_BUFF_SIZE,
                         "[%d,\"%s\",\"%s\",%s]",
                         E_OCPP_MESSAGE_CALL,
                         app_ocpp_up_data_proc[action_type].uid,
                         app_ocpp_up_data_proc[action_type].ocpp_action_name,
                         pack_buff);
            }
        }
    } else {

        if (action_type >= E_OCPP_CANCEL_RESERVATION && action_type < E_OCPP_RECV_ACTION_MAX) {
            if (E_OCPP_DATA_TRANSFER_SERVER == action_type) {
                pack_result = ocpp_down_15118_data_proc[extend_type].send_proc(pack_buff, PACK_BUFF_SIZE, result_type);
                if (pack_result < 0) {
                    goto exit;
                }
                snprintf((char *)send_buff, SEND_BUFF_SIZE,
                         "[%d,\"%s\",%s]",
                         E_OCPP_MESSAGE_CALL_RESULT,
                         ocpp_down_15118_data_proc[extend_type].uid,
                         pack_buff);
            } else {
                pack_result = app_ocpp_down_data_proc[action_type].send_proc(pack_buff, PACK_BUFF_SIZE, result_type);
                if (pack_result < 0) {
                    goto exit;
                }
                snprintf((char *)send_buff, SEND_BUFF_SIZE,
                         "[%d,\"%s\",%s]",
                         E_OCPP_MESSAGE_CALL_RESULT,
                         app_ocpp_down_data_proc[action_type].uid,
                         pack_buff);
            }
        }
    }

    ret = app_webclient_util_send(send_buff, strlen(send_buff));

exit:
    if (ret) {
        LOG_D("Pack : %.*s", strlen(send_buff), send_buff);
    }

    if (pack_buff) {
        rt_free(pack_buff);
        pack_buff = RT_NULL;
    }

    if (send_buff) {
        rt_free(send_buff);
        send_buff = RT_NULL;
    }

    return ret;
}

/*
 *接收到服务端的数据 处理
 */

bool app_ocpp_util_recv_proc(UINT16 service_id, const char *data, char *service_uid, char *action_type) {
    int i = 0, message_id = 0;
    bool ret = false;
    // 收到服务器请求数据
    if (service_id == E_OCPP_MESSAGE_CALL) {
        rt_kprintf("SERVICE_ID :%d\n", E_OCPP_MESSAGE_CALL);
        for (i = 0; i < ARRAY_SIZE(app_ocpp_down_data_proc); i++) {
            rt_kprintf("array_i :%d\n", i);
            if (strcmp(action_type, app_ocpp_down_data_proc[i].ocpp_action_name) == 0) {
                LOG_I("ocpp_action_name :%s, array_i :%d\n", app_ocpp_down_data_proc[i].ocpp_action_name, i);
                if (i == E_OCPP_DATA_TRANSFER_SERVER) {
                    rt_kprintf("TEST1\n");
                    LOG_I("TEST DATA :%s", data);
                    //					ocpp_pack_data_tran_get_message_id((char *)data, &message_id);
                    snprintf(app_ocpp_down_data_proc[i].uid,
                             sizeof(app_ocpp_down_data_proc[i].uid), "%s", service_uid);
                    ret = app_ocpp_down_data_proc[i].recv_proc((char *)data);
                    break;
                } else {
                    rt_kprintf("TEST 2\n");
                    snprintf(app_ocpp_down_data_proc[i].uid,
                             sizeof(app_ocpp_down_data_proc[i].uid), "%s", service_uid);
                    ret = app_ocpp_down_data_proc[i].recv_proc((char *)data);
                    break;
                }
            }
        }

    } else if (service_id == E_OCPP_MESSAGE_CALL_RESULT) {
        // 收到应答数据
        for (i = 0; i < ARRAY_SIZE(app_ocpp_up_data_proc); i++) {
            if (strcmp(service_uid, app_ocpp_up_data_proc[i].uid) == 0) {
                if (app_ocpp_up_data_proc[i].recv_proc != NULL) {
                    ret = app_ocpp_up_data_proc[i].recv_proc((char *)data);
                }
                break;
            }
        }
        for (i = 0; i < ARRAY_SIZE(ocpp_up_15118_data_proc); i++) {
            if (strcmp(service_uid, ocpp_up_15118_data_proc[i].uid) == 0) {
                if (ocpp_up_15118_data_proc[i].recv_proc != NULL) {
                    ret = ocpp_up_15118_data_proc[i].recv_proc((char *)data);
                }
                break;
            }
        }
    } else if (service_id == E_OCPP_MESSAGE_CALL_ERROR) {

    } else {
    }

    return ret;
}

/*
 *判断当前指令对应的枚举
 */
int app_ocpp_util_send_ation_name(char *action_name) {
    int i;
    for (i = 0; i < E_OCPP_SEND_ACTION_MAX; i++) {
        if (strcmp(action_name, app_ocpp_up_data_proc[i].ocpp_action_name) == 0) {
            break;
        }
    }
    if (i >= E_OCPP_SEND_ACTION_MAX) {
        return -1;
    }
    return i;
}
